from __future__ import annotations

"""
认证与令牌路由（auth）
---------------------
职责：
- 用户注册/登录/刷新令牌/获取当前用户信息
- 登录成功时确保在 hummingbot-api 中存在同名账户

说明：
- 使用 HTTP-only Cookie 回传 access/refresh，便于前端存储
- 部分失败场景返回明确的 4xx/5xx 错误
"""

import logging

from fastapi import APIRouter, Depends, HTTPException, Response, status
from sqlalchemy import select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession

from ..config import get_settings
from ..db import get_session
from ..deps import get_current_user
from ..models import User
from ..schemas import (
    LoginRequest,
    RefreshRequest,
    RegisterRequest,
    TokenResponse,
    UserRead,
)
from ..security.auth import (
    AuthError,
    create_token_pair,
    decode_token,
    get_password_hash,
    verify_otp,
    verify_password,
)
from ..services.hb_client import HBClientError, hb_client

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/auth", tags=["auth"])


@router.post(
    "/register",
    response_model=UserRead,
    summary="注册用户",
    description="注册新用户账号（通常仅用于初始化或测试环境）。",
)
async def register(payload: RegisterRequest, session: AsyncSession = Depends(get_session)) -> UserRead:
    """注册新用户。

    - 检查邮箱是否已存在
    - 使用 bcrypt 进行密码哈希
    - 返回用户只读信息
    """
    stmt = select(User).where(User.email == payload.email)
    result = await session.execute(stmt)
    existing = result.scalar_one_or_none()
    if existing:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered")

    user = User(
        email=payload.email,
        password_hash=get_password_hash(payload.password),
        role=payload.role,
    )
    session.add(user)
    try:
        await session.commit()
    except IntegrityError as exc:
        await session.rollback()
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Could not register user") from exc
    await session.refresh(user)
    return UserRead.from_orm(user)


@router.post(
    "/login",
    response_model=TokenResponse,
    summary="登录获取令牌",
    description="通过邮箱/密码与 OTP（若开启）登录，返回访问与刷新令牌。",
)
async def login(payload: LoginRequest, response: Response, session: AsyncSession = Depends(get_session)) -> TokenResponse:
    """用户登录。

    - 校验邮箱/密码与可选 OTP
    - 确保 hummingbot-api 中存在对应账户
    - 生成 access/refresh 并写入 Cookie
    """
    stmt = select(User).where(User.email == payload.email)
    result = await session.execute(stmt)
    user = result.scalar_one_or_none()
    if user is None or not verify_password(payload.password, user.password_hash):
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials")

    if not verify_otp(user.email, payload.otp_code):
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="OTP verification failed")

    await _ensure_user_account(user.email)

    tokens = create_token_pair(str(user.id), extra_claims={"role": user.role})
    _set_auth_cookies(response, tokens)
    return TokenResponse(**tokens)


@router.post(
    "/refresh",
    response_model=TokenResponse,
    summary="刷新访问令牌",
    description="使用刷新令牌换取新的访问令牌与刷新令牌。",
)
async def refresh(token_req: RefreshRequest, response: Response, session: AsyncSession = Depends(get_session)) -> TokenResponse:
    """刷新令牌。

    - 校验 refresh token 的类型与有效期
    - 重新生成 access/refresh 并写入 Cookie
    """
    try:
        payload = decode_token(token_req.refresh_token, expected_type="refresh")
    except AuthError as exc:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(exc)) from exc

    user_id = payload.get("sub")
    if user_id is None:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid refresh token")

    stmt = select(User).where(User.id == int(user_id))
    result = await session.execute(stmt)
    user = result.scalar_one_or_none()
    if user is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")

    tokens = create_token_pair(str(user.id), extra_claims={"role": user.role})
    _set_auth_cookies(response, tokens)
    return TokenResponse(**tokens)


@router.get(
    "/me",
    response_model=UserRead,
    summary="当前用户信息",
    description="返回当前登录用户的基本信息与设置。",
)
async def me(current_user: User = Depends(get_current_user)) -> UserRead:
    """返回当前用户信息。"""
    return UserRead.from_orm(current_user)


def _set_auth_cookies(response: Response, tokens: dict) -> None:
    settings = get_settings()
    response.set_cookie(
        "access_token",
        tokens["access_token"],
        httponly=True,
        secure=False,
        samesite="lax",
        max_age=settings.jwt_access_minutes * 60,
    )
    response.set_cookie(
        "refresh_token",
        tokens["refresh_token"],
        httponly=True,
        secure=False,
        samesite="lax",
        max_age=settings.jwt_refresh_days * 86400,
    )


async def _ensure_user_account(account_name: str) -> None:
    try:
        created = await hb_client.create_account(account_name)
        if created:
            logger.info("Created hummingbot account %s during login", account_name)
    except HBClientError as exc:
        logger.error("Failed to ensure hummingbot account %s: %s", account_name, exc)
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail="无法创建交易账户，请稍后重试。",
        ) from exc
